param([int]$Port = 8000)
$ErrorActionPreference = "Stop"

$listener = New-Object System.Net.HttpListener
$prefix = "http://localhost:$Port/"
$listener.Prefixes.Clear()
$listener.Prefixes.Add($prefix)
$listener.Start()
Write-Host "Serving HTTP on $prefix from $(Get-Location)"

function Get-ContentType($path) {
  switch ([System.IO.Path]::GetExtension($path).ToLower()) {
    ".html" { return "text/html" }
    ".htm"  { return "text/html" }
    ".css"  { return "text/css" }
    ".js"   { return "application/javascript" }
    ".json" { return "application/json" }
    ".png"  { return "image/png" }
    ".jpg"  { return "image/jpeg" }
    ".jpeg" { return "image/jpeg" }
    default  { return "text/plain" }
  }
}

while ($true) {
  $context = $listener.GetContext()
  $request = $context.Request
  $response = $context.Response

  $relPath = $request.Url.LocalPath.TrimStart("/")
  if ([string]::IsNullOrWhiteSpace($relPath)) { $relPath = "index.html" }
  $filePath = Join-Path (Get-Location) $relPath

  if (-not (Test-Path $filePath)) {
    $response.StatusCode = 404
    $bytes = [Text.Encoding]::UTF8.GetBytes("404 Not Found")
    $response.OutputStream.Write($bytes, 0, $bytes.Length)
    $response.Close()
    continue
  }

  $bytes = [System.IO.File]::ReadAllBytes($filePath)
  $response.StatusCode = 200
  $response.ContentType = Get-ContentType $filePath
  $response.ContentLength64 = $bytes.Length
  $response.OutputStream.Write($bytes, 0, $bytes.Length)
  $response.Close()
}